#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindow), inputchanged(true) {
  ui->setupUi(this);
  connect(ui->le_input, &QLineEdit::textChanged, this,
          &MainWindow::updateScramble);
  connect(ui->le_datain, &QLineEdit::textChanged, this,
          &MainWindow::updateScramble);
}

MainWindow::~MainWindow() { delete ui; }

void MainWindow::updateScramble() {
  unsigned int datain = ui->le_datain->text().toUInt(nullptr, 16);
  std::bitset<8> out = datain;
  for (int i = 0; i < 8; i++) {
    out[i] = out[i] ^ reg.bitin[reg.poly.size() - 1 - i];
  }
  ui->le_dataout->setText(
      QString("%1").arg(out.to_ullong(), 2, 16, QLatin1Char('0')).toUpper());
  qApp->processEvents();
}

LFSR::LFSR(unsigned long long coef, unsigned long long value)
    : bitin(0xFFFF), bitout(0) {
  polynomial_coefficients = coef, init_value = value;
  poly.set(coef);
}

unsigned int LFSR::getNext() {
  //  getNext16bit();
  getNextbit();
  //  for (int i = 0; i < 8; i++) {
  //    //    getNextbit_16();
  //    //    getNextbit_23();
  //    bitin = bitout;
  //  }
}

unsigned int LFSR::getNextbit() {
  std::bitset<64> &bit_out = bitout;
  std::bitset<64> &bit = bitin;
  bit_out.reset();
  for (int i = 0; i < poly.size(); i++) {
    for (auto id : poly.polyLinkList[i])
      bit_out[i] = bit_out[i] ^ bit[id];
  }
  cnt++;
}

//后面nextbit函数为初期实验用的固定函数均可试用
// unsigned int LFSR::getNextbit_8() {
//  std::bitset<64> &bit_out = bitout;
//  std::bitset<64> &bit = bitin;
//  bit_out[0] = bit[7];
//  bit_out[1] = bit[0];
//  bit_out[2] = bit[1];
//  bit_out[3] = bit[2] ^ bit[7];
//  bit_out[4] = bit[3] ^ bit[7];
//  bit_out[5] = bit[4] ^ bit[7];
//  bit_out[6] = bit[5];
//  bit_out[7] = bit[6];
//  cnt++;
//}

// unsigned int LFSR::getNextbit_16() {

//  std::bitset<64> &bit_out = bitout;
//  std::bitset<64> &bit = bitin;
//  bit_out[0] = bit[15];
//  bit_out[1] = bit[0];
//  bit_out[2] = bit[1];
//  bit_out[3] = bit[2] ^ bit[15];
//  bit_out[4] = bit[3] ^ bit[15];
//  bit_out[5] = bit[4] ^ bit[15];
//  bit_out[6] = bit[5];
//  bit_out[7] = bit[6];
//  bit_out[8] = bit[7];
//  bit_out[9] = bit[8];
//  bit_out[10] = bit[9];
//  bit_out[11] = bit[10];
//  bit_out[12] = bit[11];
//  bit_out[13] = bit[12];
//  bit_out[14] = bit[13];
//  bit_out[15] = bit[14];
//  cnt++;
//}

// unsigned int LFSR::getNextbit_23() {
//  std::bitset<64> &bit_out = bitout;
//  std::bitset<64> &bit = bitin;
//  bit_out[0] = bit[22];
//  bit_out[1] = bit[0];
//  bit_out[2] = bit[1] ^ bit[22];
//  bit_out[3] = bit[2];
//  bit_out[4] = bit[3];
//  bit_out[5] = bit[4] ^ bit[22];
//  bit_out[6] = bit[5];
//  bit_out[7] = bit[6];
//  bit_out[8] = bit[7] ^ bit[22];
//  bit_out[9] = bit[8];
//  bit_out[10] = bit[9];
//  bit_out[11] = bit[10];
//  bit_out[12] = bit[11];
//  bit_out[13] = bit[12];
//  bit_out[14] = bit[13];
//  bit_out[15] = bit[14];
//  bit_out[16] = bit[15] ^ bit[22];
//  bit_out[17] = bit[16];
//  bit_out[18] = bit[17];
//  bit_out[19] = bit[18];
//  bit_out[20] = bit[19];
//  bit_out[21] = bit[20] ^ bit[22];
//  bit_out[22] = bit[21];

//  cnt++;
//}

// unsigned int LFSR::getNext16bit() {
//  std::bitset<64> &bit_out = bitout;
//  std::bitset<64> &bit = bitin;
//  bit_out[0] = bit[8];
//  bit_out[1] = bit[9];
//  bit_out[2] = bit[10];
//  bit_out[3] = bit[11] ^ bit[8];
//  bit_out[4] = bit[12] ^ bit[9] ^ bit[8];
//  bit_out[5] = bit[13] ^ bit[10] ^ bit[9] ^ bit[8];
//  bit_out[6] = bit[14] ^ bit[11] ^ bit[10] ^ bit[9];
//  bit_out[7] = bit[15] ^ bit[12] ^ bit[11] ^ bit[10];
//  bit_out[8] = bit[0] ^ bit[13] ^ bit[12] ^ bit[11];
//  bit_out[9] = bit[1] ^ bit[14] ^ bit[13] ^ bit[12];
//  bit_out[10] = bit[2] ^ bit[15] ^ bit[14] ^ bit[13];
//  bit_out[11] = bit[3] ^ bit[15] ^ bit[14];
//  bit_out[12] = bit[4] ^ bit[15];
//  bit_out[13] = bit[5];
//  bit_out[14] = bit[6];
//  bit_out[15] = bit[7];
//  cnt++;
//}

void MainWindow::on_btn_next_clicked() {
  if (!inputchanged) {
    ui->le_input->setText(ui->le_output->text());
  } else {
    updateScramble();
    inputchanged = false;
    unsigned int in = ui->le_output->text().toUInt(nullptr, 16);
    unsigned int datain = ui->le_datain->text().toUInt(nullptr, 16);
    if (in) {
      reg.bitin = in;
      //    datain++;
      ui->le_datain->setText(
          QString("%1").arg(datain, 2, 16, QLatin1Char('0')).toUpper());
    }
    reg.getNext();
    unsigned int out = reg.bitout.to_ulong();
    ui->le_output->setText(
        QString("%1").arg(out, 4, 16, QLatin1Char('0')).toUpper());
  }
}

void MainWindow::on_le_input_textChanged(const QString &arg1) {
  unsigned int in = ui->le_input->text().toUInt(nullptr, 16);
  reg.bitin = in;
  reg.getNext();
  unsigned int out = reg.bitout.to_ulong();
  ui->le_output->setText(
      QString("%1").arg(out, 4, 16, QLatin1Char('0')).toUpper());
}

void MainWindow::on_btn_run_clicked() {
  unsigned int in = ui->le_input->text().toUInt(nullptr, 16);
  if (!in) {
    in = 0xFFFF;
  }
  reg.cnt = 0;
  reg.bitin = in;
  reg.getNext();
  ui->textEdit->append(QString("%1")
                           .arg(reg.bitout.to_ulong(), 4, 16, QLatin1Char('0'))
                           .toUpper());
  while (reg.bitout != in) {
    ui->textEdit->insertPlainText(
        QString("%1")
            .arg(reg.bitout.to_ulong(), 4, 16, QLatin1Char('0'))
            .toUpper());
    reg.bitin = reg.bitout;
    reg.getNext();
    if (reg.bitout == 0)
      break;
  }
  ui->textEdit->append(tr("count :%1").arg(reg.cnt));
}

void MainWindow::on_le_polynomial_textChanged(const QString &arg1) {
  unsigned long long po = ui->le_polynomial->text().toULongLong(nullptr, 16);
  reg.poly.set(po);
}
